﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

namespace Felbot.Interface {
    /// <summary>
    /// This custom ComboBox allows the selection of most common colors.
    /// </summary>
    public class ColorComboBox : ComboBox {
        private bool m_HideText;

        /// <summary>
        /// Show the text next to items.
        /// </summary>
        [Description("Show the text next to items.")]
        [Category("Appearance")]
        [DefaultValue(true)]
        public bool ShowText {
            get {
                return !this.m_HideText;
            }
            set {
                this.m_HideText = !value;
            }
        }

        /// <summary>
        /// Get the items of the ComboBox.
        /// </summary>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new ComboBox.ObjectCollection Items {
            get {
                return base.Items;
            }
        }
        /// <summary>
        /// Gets or sets the selected color.
        /// </summary>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Color SelectedColor {
            get {
                // Get the index of the currently selected item.
                int index = this.SelectedIndex;

                try {
                    // Sanity check the index before attempting to use it.
                    if (index == -1) {
                        if (this.Text == "")
                            return Color.Empty;
                        else {
                            string[] textSplit = this.Text.Split(",".ToCharArray(), 4, StringSplitOptions.RemoveEmptyEntries);
                            int a; int r; int g; int b;
                            if (textSplit.Length == 3) {
                                r = int.Parse(textSplit[0].Trim(" {}[]()".ToCharArray()));
                                g = int.Parse(textSplit[1].Trim(" {}[]()".ToCharArray()));
                                b = int.Parse(textSplit[2].Trim(" {}[]()".ToCharArray()));
                                return Color.FromArgb(r, g, b);
                            } else if (textSplit.Length == 4) {
                                a = int.Parse(textSplit[0].Trim(" {}[]()".ToCharArray()));
                                r = int.Parse(textSplit[1].Trim(" {}[]()".ToCharArray()));
                                g = int.Parse(textSplit[2].Trim(" {}[]()".ToCharArray()));
                                b = int.Parse(textSplit[3].Trim(" {}[]()".ToCharArray()));
                                return Color.FromArgb(a, r, g, b);
                            } else if (textSplit.Length == 1)
                                return Color.FromArgb(int.Parse(this.Text.Trim(" {}[]()".ToCharArray())));
                            else
                                return Color.Empty;
                        }
                    }
                    // Return the corresponding font family.
                    return GetColorFromString(this.SelectedItem.ToString());
                } catch (ArgumentException) {
                    return Color.Empty;
                } catch (FormatException) {
                    return Color.Empty;
                }
            }
            set {
                int index = -1;

                // Should we look for a matching item?
                if (value.IsEmpty) {
                    this.Text = "";
                } else {
                    if (value.IsNamedColor) {
                        index = this.FindString(GetStringFromColor(value), 0);
                        // Select the item.
                        this.SelectedIndex = index;
                    } else {
                        this.Text = "{" + value.R.ToString() + ", " + value.G.ToString() + "," + value.B.ToString() + "}";
                    }
                }
            }
        }

        /// <summary>Creates a color combo box.</summary>
        public ColorComboBox() {
            IEnumerator c = Enum.GetValues(new KnownColor().GetType()).GetEnumerator();
            Color d;
            while (c.MoveNext()) {
                d = Color.FromKnownColor((KnownColor) c.Current);
                this.Items.Add(GetStringFromColor(d));
            }
            this.DrawMode = DrawMode.OwnerDrawFixed;
        }

        /// <summary>
        /// Draws the color in the combobox.
        /// </summary>
        /// <param name="e">The event args.</param>
        protected override void OnDrawItem(DrawItemEventArgs e) {
            base.OnDrawItem(e);
            e.DrawBackground();
            if ((e.State & DrawItemState.Focus) != 0)
                e.DrawFocusRectangle();
            Graphics grfx = e.Graphics;
            Color brushColor = GetColorFromString((string) this.Items[e.Index]);
            SolidBrush brush = new SolidBrush(brushColor);

            Rectangle colorSpot = new Rectangle(e.Bounds.Left + 2, e.Bounds.Top + 2, 30, e.Bounds.Height - 4);
            Rectangle textSpot = new Rectangle(e.Bounds.Left + 34, e.Bounds.Top, e.Bounds.Width - 34, e.Bounds.Height);
            SolidBrush blackBrush = new SolidBrush(Color.Black);
            Pen blackPen = new Pen(blackBrush, 1F);
            grfx.FillRectangle(brush, colorSpot);
            grfx.DrawRectangle(blackPen, colorSpot);

            if (!m_HideText) {
                grfx.DrawString((string) this.Items[e.Index], e.Font, blackBrush, textSpot);
            }
        }

        /// <summary>Gets the name of a color.</summary>
        /// <param name="color">The color.</param>
        /// <returns>The color name as a string.</returns>
        public string GetStringFromColor(Color color) {
            string colorName = color.Name.Substring(0, 1);
            for (int i = 1; i < color.Name.Length; i++) {
                if (color.Name.Substring(i, 1) == color.Name.Substring(i, 1).ToUpper())
                    colorName = colorName + " " + color.Name.Substring(i, 1);
                else
                    colorName = colorName + color.Name.Substring(i, 1);
            }
            return colorName;
        }

        /// <summary>Gets the color from a name.</summary>
        /// <param name="strColorName">The name.</param>
        /// <returns>The color as a Color.</returns>
        public Color GetColorFromString(string colorName) {
            return Color.FromName(colorName.Replace(" ", ""));
        }
    }
}
